package hr.ctg.web.resource;

import hr.ctg.domain.model.Slika;
import hr.ctg.service.dao.SlikaDAO;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.ImageIcon;

import org.jboss.seam.Component;
import org.jboss.seam.cache.CacheProvider;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
import org.jboss.seam.web.AbstractResource;

//@Scope(ScopeType.APPLICATION)
//@Name("photoResource")
//@BypassInterceptors
public class ImageResource extends AbstractResource {

	/**
	 * The maximum width allowed for image rescaling
	 */
	private static final int MAX_IMAGE_WIDTH = 800;
	// private static final int MAX_IMAGE_HEIGHT = 600;

	private byte[] noImage;

	@Override
	public void getResource(final HttpServletRequest req,
			final HttpServletResponse res) throws ServletException, IOException {
		try {
			new ContextualHttpServletRequest(req) {
				@Override
				public void process() throws IOException {
					final BufferedOutputStream outputStream = new BufferedOutputStream(
							res.getOutputStream());
					try {
						final String idSlike = req.getParameter("idSlike");
						final String idObjekta = req.getParameter("idObjekta");
						final String idParka = req.getParameter("idParka");
						final String idMjesta = req.getParameter("idMjesta");
						final String idOtoka = req.getParameter("idOtoka");
						final String idDogadjaja = req
								.getParameter("idDogadjaja");
						Slika slika = null;
						if (idSlike != null) {
							slika = getSlika(Integer.parseInt(idSlike));
						} else if (idObjekta != null) {
							slika = getSlikaByIdObjekta(Integer
									.parseInt(idObjekta));
						} else if (idMjesta != null) {
							slika = getSlikaByIdMjesta(Integer
									.parseInt(idMjesta));
						} else if (idOtoka != null) {
							slika = getSlikaByIdOtoka(Integer.parseInt(idOtoka));
						} else if (idParka != null) {
							slika = getSlikaByIdParka(Integer.parseInt(idParka));
						} else if (idDogadjaja != null) {
							slika = getSlikaByIdDogadjaja(Integer
									.parseInt(idDogadjaja));
						}

						String contentType = null;
						byte[] data = null;

						if (slika != null && slika.getSadrzaj() != null
								&& slika.getSadrzaj().length > 0) {
							contentType = slika.getTipSadrzaja();
							data = slika.getSadrzaj();
						} else if (getNoImage() != null) {
							contentType = "image/png";
							data = getNoImage();
						}

						if (data != null) {
							res.setContentType(contentType);

							boolean rescale = false;
							int width = 0;
							int height = -1;
							ImageIcon icon = new ImageIcon(data);
							;

							// Check if the image needs to be rescaled
							if (req.getParameter("width") != null) {
								width = Math.min(MAX_IMAGE_WIDTH, Integer
										.parseInt(req.getParameter("width")));
								if (width > 0 && width != icon.getIconWidth()) {
									rescale = true;
								}
							}
							if (req.getParameter("height") != null) {
								height = Integer.parseInt(req
										.getParameter("height"));
							}
							if (req.getParameter("width") == null
									&& MAX_IMAGE_WIDTH < icon.getIconWidth()) {
								rescale = true;
								width = MAX_IMAGE_WIDTH;
							}

							// Rescale the image if required
							if (rescale) {
								final double ratio = (double) width
										/ icon.getIconWidth();
								height = height == -1 ? (int) (icon
										.getIconHeight() * ratio) : height;

								final int imageType = "image/png"
										.equals(contentType) ? BufferedImage.TYPE_INT_ARGB
										: BufferedImage.TYPE_INT_RGB;
								final BufferedImage bImg = new BufferedImage(
										width, height, imageType);
								final Graphics2D g2d = bImg.createGraphics();
								g2d
										.setRenderingHint(
												RenderingHints.KEY_INTERPOLATION,
												RenderingHints.VALUE_INTERPOLATION_BICUBIC);
								g2d.drawImage(icon.getImage(), 0, 0, width,
										height, null);
								g2d.dispose();

								String formatName = "";
								if ("image/png".equals(contentType)) {
									formatName = "png";
								} else if ("image/jpeg".equals(contentType)
										|| "image/pjpeg".equals(contentType)) {
									formatName = "jpeg";
								} else if ("image/gif".equals(contentType)) {
									formatName = "gif";
								}

								ImageIO.write(bImg, formatName, outputStream);
							} else {
								outputStream.write(data);
							}
						}
					} catch (final NoClassDefFoundError e) {
					}

					outputStream.flush();
					outputStream.close();
				}
			}.run();
		} catch (final ClassCastException e) {

		}
	}

	private byte[] getNoImage() {
		if (noImage == null) {
			final InputStream in = getServletContext().getResourceAsStream(
					"/resources/images/no_image.png");
			if (in != null) {
				final ByteArrayOutputStream out = new ByteArrayOutputStream();
				final byte[] buffer = new byte[512];
				try {
					int read = in.read(buffer);
					while (read != -1) {
						out.write(buffer, 0, read);
						read = in.read(buffer);
					}

					noImage = out.toByteArray();
				} catch (final IOException e) {
				}
			}
		}
		return noImage;
	}

	private Slika getSlika(final Integer idSlike) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idSlike_" + idSlike);
		if (s == null) {
			s = slikaDAO.find(idSlike);
			if (s != null) {
				putInCache("idSlike_" + idSlike, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdObjekta(final Integer idObjekta) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idObjekta_" + idObjekta);
		if (s == null) {
			s = slikaDAO.findByIdObjektaP(idObjekta);
			if (s != null) {
				putInCache("idObjekta_" + idObjekta, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdMjesta(final Integer idMjesta) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idMjesta_" + idMjesta);
		if (s == null) {
			s = slikaDAO.findByIdMjestaP(idMjesta);
			if (s != null) {
				putInCache("idMjesta_" + idMjesta, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdOtoka(final Integer idOtoka) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idOtoka_" + idOtoka);
		if (s == null) {
			s = slikaDAO.findByIdOtokaP(idOtoka);
			if (s != null) {
				putInCache("idOtoka_" + idOtoka, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdParka(final Integer idParka) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idParka_" + idParka);
		if (s == null) {
			s = slikaDAO.findByIdParkaP(idParka);
			if (s != null) {
				putInCache("idParka_" + idParka, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdDogadjaja(final Integer idDogadjaja) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idDogadjaja_" + idDogadjaja);
		if (s == null) {
			s = slikaDAO.findByIdDogadjajaP(idDogadjaja);
			if (s != null) {
				putInCache("idDogadjaja_" + idDogadjaja, s);
			}
		}
		return s;
	}

	@SuppressWarnings("unchecked")
	private Slika getFromCache(final String name) {
		final CacheProvider cacheProvider = (CacheProvider) Component
				.getInstance("org.jboss.seam.cache.cacheProvider");
		Slika s = null;

		s = (Slika) cacheProvider.get("slike", name);

		return s;
	}

	@SuppressWarnings("unchecked")
	private void putInCache(final String name, final Slika value) {
		final CacheProvider cacheProvider = (CacheProvider) Component
				.getInstance("org.jboss.seam.cache.cacheProvider");

		cacheProvider.put("slike", name, value);

	}

	@Override
	public String getResourcePath() {
		return "/image";
	}

}
